﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;

namespace Aquasoft.Iszr.Proxy.WebServices
{
    public class LoggingMessageInterceptor : IIszrMessageInterceptor
    {
        public System.Net.WebResponse GetWebResponse(IszrServiceBase service, System.Net.WebRequest request)
        {
            return null;
        }

        public System.Net.WebResponse GetWebResponseAsync(IszrServiceBase service, System.Net.WebRequest request, IAsyncResult result)
        {
            return null;
        }

        public System.Net.WebRequest GetWebRequest(IszrServiceBase service, Uri uri)
        {
            return null;
        }

        public System.Xml.XmlReader GetReaderForMessage(IszrServiceBase service, System.Web.Services.Protocols.SoapClientMessage message, int bufferSize)
        {
            var ms = new MemoryStream();
            message.Stream.CopyTo(ms);
            ms.Seek(0, SeekOrigin.Begin);

            XmlTextReader reader = new XmlTextReader(new StreamReader(ms, new UTF8Encoding(false), true, bufferSize));

            reader.DtdProcessing = DtdProcessing.Prohibit;
            reader.Normalization = true;
            reader.XmlResolver = null;

            return reader;
        }

        public System.Xml.XmlWriter GetWriterForMessage(IszrServiceBase service, System.Web.Services.Protocols.SoapClientMessage message, int bufferSize)
        {
            var logStream = new MemoryStream();
            var writer = new XmlTextWriter(new StreamWriter(new DelegatingWriteStream(message.Stream, logStream), service.RequestEncoding ?? new UTF8Encoding(false), bufferSize));
            writer.Formatting = Formatting.Indented;
            return writer;
        }

        class DelegatingWriteStream : Stream
        {
            private readonly Stream innerStream;
            private readonly Stream logStream;

            public DelegatingWriteStream(Stream innerStream, Stream logStream)
            {
                if (innerStream == null)
                    throw new ArgumentNullException("innerStream");
                if (logStream == null)
                    throw new ArgumentNullException("logStream");

                this.innerStream = innerStream;
                this.logStream = logStream;
            }

            #region Overrides of Stream

            public override void Flush()
            {
                innerStream.Flush();
                logStream.Flush();
            }

            public override long Seek(long offset, SeekOrigin origin)
            {
                var r = innerStream.Seek(offset, origin);
                logStream.Seek(offset, origin);
                return r;
            }

            public override void SetLength(long value)
            {
                innerStream.SetLength(value);
                logStream.SetLength(value);
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                throw new NotSupportedException();
                // MiKo: bohuzel pri nacitani response si nacita jen potrebna data (jakmile narazi na konecny element, tak dal nenacita - prichazi se o konmentare na konci streamu)

                //int cnt = innerStream.Read(buffer, offset, count);
                //logStream.Write(buffer, 0, cnt);
                //return cnt;
            }

            public override void Write(byte[] buffer, int offset, int count)
            {
                innerStream.Write(buffer, offset, count);
                logStream.Write(buffer, offset, count);
            }

            public override bool CanRead
            {
                get { return innerStream.CanRead; }
            }

            public override bool CanSeek
            {
                get { return innerStream.CanSeek; }
            }

            public override bool CanWrite
            {
                get { return innerStream.CanWrite; }
            }

            public override long Length
            {
                get { return innerStream.Length; }
            }

            public override long Position
            {
                get { return innerStream.Position; }
                set
                {
                    innerStream.Position = value;
                    logStream.Position = value;
                }
            }

            #endregion
        }
    }
}
